package org.sensation.server.operation;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;

import org.sensation.server.operation.command.CommandController;
import org.sensation.server.operation.request.OperationRequest;
import org.sensation.server.operation.request.analys.OperationRequestAnalys;
import org.sensation.server.operation.request.analys.OperationRequestRMIAnalyst;
import org.sensation.server.operation.response.Response;

public class SensationOperationAnalyst implements Runnable{
	private Socket socket;
	private InputStream inputStream;
	private OutputStream outputStream;
	private OperationRequestAnalys operationRequestAnalys;
	private Map<String, CommandController> controllers;
	
	public SensationOperationAnalyst(Map<String, CommandController> controllers, Socket socket) throws IOException {
		super();
		this.socket = socket;
		this.operationRequestAnalys = new OperationRequestRMIAnalyst();
		this.controllers = controllers;
	}
	
	public void run() {
		try {
			getStreamFromSocket();
			commandControllerServiceAndRequestAnalysis();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				closeAll();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void getStreamFromSocket() throws IOException {
		inputStream = socket.getInputStream();
		outputStream = socket.getOutputStream();
	}
	
	private void commandControllerServiceAndRequestAnalysis() throws Exception {
		String hostName = getClientHostName();
		OperationRequest request = requestAnalysis(hostName);
		Response response = responseAnalysis();
		
		commandControllerService(request, response);
	}

	private void commandControllerService(OperationRequest request,
			Response response) throws Exception {
		CommandController controller = getCommandController(request);
		controller.service(request, response);
	}

	private OperationRequest requestAnalysis(String hostName)
			throws Exception {
		return operationRequestAnalys.analysis(inputStream, hostName);
	}
	
	private Response responseAnalysis() throws IOException {
		Response response = new Response(outputStream);
		return response;
	}
	
	private CommandController getCommandController(OperationRequest request) {
		String name = request.getCommand();
		CommandController controller = controllers.get(name);
		return controller;
	}
	
	private String getClientHostName(){
		return socket.getInetAddress().getHostName();
	}
	
	
	public void closeAll() throws IOException {
		if(socket != null)
			closeSocket();
		if(inputStream != null)
			closeInputStream();
		if(outputStream != null)
			closeOutputStream();
	}

	private void closeOutputStream() throws IOException {
		try {
			outputStream.close();
		} catch (IOException e) {
			outputStream.close();
			e.printStackTrace();
		}
	}

	private void closeInputStream() throws IOException {
		try {
			inputStream.close();
		} catch (IOException e) {
			inputStream.close();
			e.printStackTrace();
		}
	}

	private void closeSocket() throws IOException {
		try {
			socket.close();
		} catch (IOException e) {
			socket.close();
			e.printStackTrace();
		}
	}
}